#pragma once

#include <iostream>
#include <string>
#include <cassert>
#include <typeinfo>
#include <typeindex>
#include <initializer_list>

#include <glm/glm.hpp>

#include "OMIT_MeshAttrMacros.h"

namespace OMIT_NAMESPACE
{
    namespace detail
    {
        template <typename Derived>
        struct _MeshAttr_Base
        {
            constexpr static OMIT_MESHATTR_OUTPUT_IDXTYPE UUID()
            {
                return Derived::UUID();
            }

            auto GetValue() const
            {
                return static_cast<const Derived*>(this)->Value();
            }

            static std::string GetName() { return Derived::Name(); }
        };
    }

    // 几何属性定义在 geomAttr 命名空间下，如
    // 1. 三维坐标 coord3f
    // 2. 空间法向 norm3f
    // 3. 长度 lengthf
    // 4. 面积 areaf
    namespace geomAttr
    {
        OMIT_MESHATTR_DEFINE_ATTR(Coord3f, coord3f, Coord,  glm::vec<3, float>);
        OMIT_MESHATTR_DEFINE_ATTR(Norm3f,  norm3f,  Norm,   glm::vec<3, float>);
        OMIT_MESHATTR_DEFINE_ATTR(Lengthf, lenfthf, Length, float);
        OMIT_MESHATTR_DEFINE_ATTR(Areaf,   areaf,   Area,   float);
    }
    // 质量属性定义在 qualityAttr 命名空间下，如
    // 1. 偏斜 skewf
    // 2. 横纵比 aspectRatiof
    // 3. 正交质量 orthogonal
    namespace qualityAttr
    {
        OMIT_MESHATTR_DEFINE_ATTR(Skewnessf,    skewf,      Skewness,       float);
        OMIT_MESHATTR_DEFINE_ATTR(AspectRatiof, aspRatiof,  AspectRatio,    float);
        OMIT_MESHATTR_DEFINE_ATTR(Orthogonal,   orthof,     Orthogonal,     float);
    }

    // 辅助属性定义在 auxAttr 命名空间下，如
    // 1. rgb 颜色 color3f
    // 2. rgba 颜色 color4f
    // 3. rgb 颜色（8bit）color3u8
    // 4. rgba 颜色（8bit）color4u8
    namespace auxAttr
    {
        OMIT_MESHATTR_DEFINE_ATTR(Color3f,  color3f,    Color3f,    glm::vec<3, float>);
        OMIT_MESHATTR_DEFINE_ATTR(Color4f,  color4f,    Color4f,    glm::vec<4, float>);
        OMIT_MESHATTR_DEFINE_ATTR(Color3u8, color3u8,   Color3u8,   glm::vec<3, uint8_t>);
        OMIT_MESHATTR_DEFINE_ATTR(Color4u8, color4u8,   Color4u8,   glm::vec<4, uint8_t>);
    }
}

namespace OMIT_NAMESPACE
{
    namespace detail
    {
        inline OMIT_MESHATTR_OUTPUT_NUMOPS _MeshAttr_OutputOPs_ByUUID()
        {
            return {};
        }

        inline OMIT_MESHATTR_OUTPUT_NUMOPS _MeshAttr_OutputOPs_ByUUID(
            const std::initializer_list<OMIT_MESHATTR_OUTPUT_IDXTYPE>& UUIDs)
        {
            return OMIT_MESHATTR_OUTPUT_NUMOPS{ UUIDs };
        }

        template <typename... TAttrs>
        inline OMIT_MESHATTR_OUTPUT_NUMOPS _MeshAttr_OutputOPs_ByUUID(TAttrs... UUIDs)
        {
            return OMIT_MESHATTR_OUTPUT_NUMOPS{ UUIDs... };
        }

        template <typename... TAttrs>
        OMIT_MESHATTR_OUTPUT_NUMOPS _MeshAttr_OutputOPs_ByType()
        {
            return _MeshAttr_OutputOPs_ByUUID(TAttrs::UUID()...);
        }
    }
}